HDU 5737 Differencia(归并树)
题意:
$N\le 10^5长度的A,B两个数组,A_i,B_i\le 10^9$
$Q\le 3\times 10^6次查询,2种查询$
$+ l r x:把A数组的[l, r]区间数变为x$
$? l r:查询[l, r]区间A_i\ge B_i的下标个数$
分析:
$首先O(qlog^2)的归并树做法很显然,每个节点维护B数组的有序表$
$之后对于每次查询只需要在每个节点二分一下即可$
$由于Q巨大,所以这么做要T,事实上由于不会操作B数组,对于查询可以提前维护一点东西$
$维护有序表第i个数进入左右子树时的位置(即有多少数\le 第i个数)$ $那么查询在线段树上就可以O(1)得到这个数在左右子树的rank变化$ $这个对线段树往下push lazy标记也是适用的,就去掉了1个log$
$时间复杂度O(qlogn)就可以草过去了$
代码:
//
// Created by TaoSama on 2016-07-25
// Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
int n, q, A, B;
int a[N], b[N];
int rnd(int& last, int& a, int& b) {
int C = ~(1 << 31), M = (1 << 16) - 1;
a = (36969 + (last >> 3)) * (a & M) + (a >> 16);
b = (18000 + (last >> 3)) * (b & M) + (b >> 16);
return (C & ((a << 16) + b)) % 1000000000;
}
namespace Discretization {
vector<int> xs;
void init() {
xs = vector<int>(b + 1, b + 1 + n);
sort(xs.begin(), xs.end());
for(int i = 1; i <= n; ++i) {
b[i] = lower_bound(xs.begin(), xs.end(), b[i]) - xs.begin() + 1;
a[i] = upper_bound(xs.begin(), xs.end(), a[i]) - xs.begin();
}
}
int get(int x) {
return upper_bound(xs.begin(), xs.end(), x) - xs.begin();
}
}
namespace Allocator {
int data[N << 6], *p;
void init() {
p = data;
}
int* allocate(int len) {
p += len;
return p - len;
}
}
struct Node {
int* indexLeft, *indexRight;
int tag, sum;
void setTag(int v) {
tag = sum = v;
}
int goLeft(int v) {
if(v) return indexLeft[v];
return 0;
}
int goRight(int v) {
if(v) return indexRight[v];
return 0;
}
} tree[N << 2];
void pushUp(int rt) {
tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;
}
void pushDown(int rt) {
if(~tree[rt].tag) {
int v = tree[rt].tag;
int ls = rt << 1, rs = ls | 1;
tree[ls].setTag(tree[rt].goLeft(v));
tree[rs].setTag(tree[rt].goRight(v));
tree[rt].tag = -1;
}
}
void merge(int rt, int l, int r) {
static int tmp[N];
int m = l + r >> 1;
int* vl = b + l - 1, *vr = b + m;
int sl = m - l + 1, sr = r - m;
int i = 1, j = 1, k = 1;
while(i <= sl && j <= sr) {
if(vl[i] < vr[j]) {
tree[rt].indexLeft[k] = i;
tree[rt].indexRight[k] = j - 1;
tmp[k++] = vl[i++];
} else {
tree[rt].indexLeft[k] = i - 1;
tree[rt].indexRight[k] = j;
tmp[k++] = vr[j++];
}
}
while(i <= sl) {
tree[rt].indexLeft[k] = i;
tree[rt].indexRight[k] = j - 1;
tmp[k++] = vl[i++];
}
while(j <= sr) {
tree[rt].indexLeft[k] = i - 1;
tree[rt].indexRight[k] = j;
tmp[k++] = vr[j++];
}
memcpy(b + l, tmp + 1, r - l + 1 << 2);
}
void build(int l, int r, int rt) {
tree[rt].tag = -1;
tree[rt].indexLeft = Allocator::allocate(r - l + 1);
tree[rt].indexRight = Allocator::allocate(r - l + 1);
if(l == r) {
tree[rt].sum = a[l] >= b[l];
return;
}
int m = l + r >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushUp(rt);
merge(rt, l, r);
}
void update(int L, int R, int v, int l, int r, int rt) {
if(L <= l && r <= R) {
tree[rt].setTag(v);
return;
}
int m = l + r >> 1;
pushDown(rt);
if(L <= m) update(L, R, tree[rt].goLeft(v), l, m, rt << 1);
if(R > m) update(L, R, tree[rt].goRight(v), m + 1, r, rt << 1 | 1);
pushUp(rt);
}
int query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) return tree[rt].sum;
int m = l + r >> 1, ret = 0;
pushDown(rt);
if(L <= m) ret += query(L, R, l, m, rt << 1);
if(R > m) ret += query(L, R, m + 1, r, rt << 1 | 1);
return ret;
}
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
clock_t _ = clock();
int t; scanf("%d", &t);
while(t--) {
scanf("%d%d%d%d", &n, &q, &A, &B);
for(int i = 1; i <= n; ++i) scanf("%d", a + i);
for(int i = 1; i <= n; ++i) scanf("%d", b + i);
Allocator::init();
Discretization::init();
build(1, n, 1);
int ans = 0, last = 0;
for(int i = 1; i <= q; ++i) {
int l = rnd(last, A, B) % n + 1;
int r = rnd(last, A, B) % n + 1;
int x = rnd(last, A, B) + 1;
if(l > r) swap(l, r);
if(l + r + x & 1) {
x = Discretization::get(x);
// printf("+ %d %d %d\n", l, r, x);
update(l, r, x, 1, n, 1);
} else {
last = query(l, r, 1, n, 1);
// printf("? %d %d ans = %d\n", l, r, last);
ans += 1LL * i * last % MOD;
if(ans >= MOD) ans -= MOD;
}
}
printf("%d\n", ans);
}
#ifdef LOCAL
printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
#endif
return 0;
}
/*
+ 2 3 5
? 2 2 ans = 1
? 1 4 ans = 3
? 2 4 ans = 2
? 3 4 ans = 1
+ 1 1 5
+ 1 5 5
? 5 5 ans = 1
? 5 5 ans = 1
? 1 4 ans = 4
81
+ 1 4 5
? 4 5 ans = 1
? 2 4 ans = 3
? 3 4 ans = 2
+ 1 5 5
? 2 5 ans = 4
+ 1 4 5
? 4 4 ans = 1
? 1 3 ans = 3
? 2 2 ans = 1
88
? 1 5 ans = 3
+ 4 4 5
+ 2 4 5
+ 3 4 5
? 3 4 ans = 2
? 1 4 ans = 4
+ 1 1 5
+ 3 5 5
+ 1 3 5
? 1 5 ans = 5
87
*/